#include <sqlite.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <cstring>

struct Info {
  std::string name;
  int age;
  bool man;
};

int queryInfo(sqlite3 *db, std::vector<Info> &vi) {
  if (!db) return SQLITE_ERROR;
  vi.clear();
  sqlite3_stmt *stmt = nullptr;
  auto sql = "SELECT * FROM test";
  auto rc = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, nullptr);
  if (rc == SQLITE_OK) {
    while (sqlite3_step(stmt) == SQLITE_ROW) {
      auto cols = sqlite3_column_count(stmt);
      Info info;
      info.age = 0; info.man = 0;
      for (int i = 0; i < cols; ++i) {
        std::string colName = sqlite3_column_name(stmt, i);
        if (colName == "name") {
          info.name = (const char *)sqlite3_column_text(stmt, i);
        } else if (colName == "age") {
          info.age = sqlite3_column_int(stmt, i);
        } else if (colName == "sex") {
          info.man = sqlite3_column_int(stmt, i) == 1 ? true : false;
        }
      }
      if (!info.name.empty()) {
        vi.emplace_back(info);
      }
    }
  }

  sqlite3_finalize(stmt);
  return rc;
}

int insertInfo(sqlite3 *db, const Info &info) {
  if (!db) return SQLITE_ERROR;

  sqlite3_stmt *stmt = nullptr;
  int rc = SQLITE_OK;
  if (rc == SQLITE_OK) {
    auto sql = "INSERT INTO test(name,age,sex) VALUES(?,?,?)";
    rc = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, nullptr);
  }

  int i = 1;
  if (rc == SQLITE_OK)
    rc = sqlite3_bind_text(stmt, i++, info.name.c_str(), info.name.length(), nullptr);

  if (rc == SQLITE_OK)
    rc = sqlite3_bind_int(stmt, i++, info.age);

  if (rc == SQLITE_OK)
    rc = sqlite3_bind_int(stmt, i++, info.man ? 1 : 0);

  if (rc == SQLITE_OK)
    rc = sqlite3_step(stmt);

  if (rc == SQLITE_DONE)
    rc = SQLITE_OK;

  sqlite3_finalize(stmt);
  return rc;
}

int deleteInfo(sqlite3 *db) {
  const char *sql = "DELETE FROM test WHERE name IN ('dzlua','kally','keke')";
  return sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
}

int checkTable(sqlite3 *db) {
  const char *sql = "CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER NOT NULL, sex INTEGER NOT NULL)";
  return sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
}

int main(int argc, char *argv[]) {
  sqlite3 *db = nullptr;
  auto rc = sqlite3_open("sqlite3.db", &db);
  if (rc != SQLITE_OK) {
    std::cout << "open error: " << sqlite3_errstr(rc) << std::endl;
    return 0;
  }

  rc = checkTable(db);
  if (rc != SQLITE_OK) {
    std::cout << "exec error: " << sqlite3_errstr(rc) << std::endl;
    sqlite3_close(db);
    return 0;
  }

  rc = deleteInfo(db);

  static Info infos[] = {
    { "dzlua", 18, true },
    { "kally", 18, false },
    { "keke", 1, true },
  };

  for (int i = 0; i < 3; ++i) {
    rc = insertInfo(db, infos[i]);
    if (rc != SQLITE_OK)
      std::cout << "insert error: " << sqlite3_errstr(rc) << std::endl;
  }

  std::vector<Info> vi;
  rc = queryInfo(db, vi);
  if (rc == SQLITE_OK) {
    for (auto it = vi.begin(); it != vi.end(); ++it) {
      std::cout << "name: " << it->name
          << ", age: " << it->age
          << ", man: " << (it->man ? "true" : "false")
          << std::endl;
    }
  } else {
    std::cout << "query error: " << sqlite3_errstr(rc) << std::endl;
  } 

  sqlite3_close(db);
  return 0;
}
